package com.atguigu.gulimall.product.bn.controller;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/*
* 织语环境签名校验
*
*
* */
@Slf4j
@Controller
public class createSignDemo {
    public static void main(String[] args) {
        //d906097865e4364f05d5609c9558f41a
        Map<String, Object> urlParams = new HashMap<>();
        urlParams.put("access_token","BL4DkrOk7A56MfG3IuAvN6lOKtBusLHE");
//        String str1="{\n" +
//                "   \"app_id\":\"8901714858135222\",\n" +
//                "   \"accounts\":[\"wjj\"]\n" +
//                "\n" +
//                "}";
        String str1=null;
        JSONObject jsonObject = JSONObject.parseObject(str1);
        Map<String, String> signatureHeader = getSignatureHeader(jsonObject, urlParams, "v1xBAgra4mZTHh07syrsGbYIA3ixBtfo");
        System.out.println(signatureHeader);
    }
    public  String getQianMing(String body,String access_token,String key){
        Map<String, Object> urlParams = new HashMap<>();
        urlParams.put("access_token",access_token);
        String str1=body;
        JSONObject jsonObject = JSONObject.parseObject(str1);
        Map<String, String> signatureHeader = getSignatureHeader(jsonObject, urlParams, key);
        System.out.println(signatureHeader);

        return signatureHeader.get("signature");
    }

    @PostMapping("/signature")
    @ResponseBody
    public   Map<String, String> signature(@RequestBody(required =false) String body, @RequestParam Map<String, Object> urlParams, String app_secret){
        JSONObject jsonObject = JSONObject.parseObject(body);
        urlParams.remove("app_secret");
        Map<String, String> signatureHeader=getSignatureHeader(jsonObject,urlParams,app_secret);
        return signatureHeader;
    }
    @PostMapping("/signature1")
    @ResponseBody
    public  Map<String, String> signature1(@RequestBody Map<String, Object> body, String access_token, String app_secret){
        System.out.println(body.get("app_id"));
        return null;
    }

    /**
     * 签名
     * @param nonce
     * @param timestamp
     * @param urlParams
     * @param body
     * @param secretKey
     * @return
     */
    public static String encrypt(String nonce, String timestamp, Map<String, Object> urlParams, JSONObject body, String secretKey){

        try{
            Map<String, Object> map = new TreeMap<>();
            map.put("nonce", "1234");
            map.put("timestamp", "1234");
            //使用Tree做参数字典排序
            Map<String, Object> paramTree = new TreeMap<>();
            if (body != null) {
                paramTree.putAll(body);
            }
            // 将url的一些参数合并进请求体中
            if(urlParams != null){
                paramTree.putAll(urlParams);
            }
            // 对需要加密的body字符串做中文unicode
            map.put("body", jsonEncode(paramTree));
//            map.put("body", paramTree);
            // pathInfo 参数
//            map.put("urlParams", urlParams);
            map.put("urlParams", getUrlEncode(urlParams));
            // 密钥
            map.put("secretKey", secretKey);
            log.info("签名数据 {}", map);
            log.info("签名数据 {}", JSONObject.toJSONString(map).replace("/", "\\/"));
            return DigestUtils.md5Hex(JSONObject.toJSONString(map).replace("/", "\\/"));
        }
        catch (Exception e){
            log.error("IM 获取加密签名失败：{}", e.getMessage());
        }
        return null;
    }


    /**
     *
     * @param body
     * @param urlParams 需要使用TreeMap 自带排序
     * @param secretKey
     * @return
     */

    public static Map<String, String> getSignatureHeader(JSONObject body, Map<String, Object> urlParams, String secretKey){
        try{
            String nonce = String.valueOf(System.currentTimeMillis() - 1000);
            String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
            String encryptStr = encrypt(nonce, timestamp, urlParams, body, secretKey);
            Map<String, String> headers = new HashMap<>();
            headers.put("nonce", "1234");
            headers.put("timestamp", "1234");
            headers.put("signature", encryptStr);
            return headers;
        }catch (Exception e){
            log.error("IM 获取加密签名工具失败：{}", e.getMessage());
        }
        return null;
    }


    private static String getUrlEncode(Map<String, Object> map){
        if (map == null) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, Object> entry : map.entrySet()) {

            try {
                sb.append(entry.getKey() + "=" + URLEncoder.encode(entry.getValue().toString(), "UTF-8"));
            } catch (Exception e) {
                sb.append(entry.getKey() + "=" + entry.getValue());
            }
            sb.append("&");
        }
        String str = sb.toString();
        if(StringUtils.isNotBlank(str)){
            return str.substring(0, str.length() - 1);
        }
        return "";

    }

    private static String jsonEncode(Object map) throws JsonProcessingException {
        String s = new ObjectMapper().writeValueAsString(map);
        s = escapeJava(s).replace("\\\"", "\"").replace("/", "\\/");
        return s;
    }

    private static String escapeJava(String str) {
        return escapeJavaStyleString(str, false, false);
    }

    private static String escapeJavaStyleString(String str, boolean escapeSingleQuotes, boolean escapeForwardSlash) {
        if (str == null) {
            return null;
        }
        try {
            StringWriter writer = new StringWriter(str.length() * 2);
            escapeJavaStyleString(writer, str, escapeSingleQuotes, escapeForwardSlash);
            return writer.toString();
        } catch (IOException ioe) {
            // this should never ever happen while writing to a StringWriter
//            throw new UnhandledException(ioe);
           return str;

        }
    }

    private static void escapeJavaStyleString(Writer out, String str, boolean escapeSingleQuote,
                                             boolean escapeForwardSlash) throws IOException {
        if (out == null) {
            throw new IllegalArgumentException("The Writer must not be null");
        }
        if (str == null) {
            return;
        }
        int sz;
        sz = str.length();
        for (int i = 0; i < sz; i++) {
            char ch = str.charAt(i);

            // handle unicode
            if (ch > 0xfff) {
                out.write("\\u" + hex(ch));
            } else if (ch > 0xff) {
                out.write("\\u0" + hex(ch));
            } else if (ch > 0x7f) {
                out.write("\\u00" + hex(ch));
            } else if (ch < 32) {
                switch (ch) {
                    case '\b' :
                        out.write('\\');
                        out.write('b');
                        break;
                    case '\n' :
                        out.write('\\');
                        out.write('n');
                        break;
                    case '\t' :
                        out.write('\\');
                        out.write('t');
                        break;
                    case '\f' :
                        out.write('\\');
                        out.write('f');
                        break;
                    case '\r' :
                        out.write('\\');
                        out.write('r');
                        break;
                    default :
                        if (ch > 0xf) {
                            out.write("\\u00" + hex(ch));
                        } else {
                            out.write("\\u000" + hex(ch));
                        }
                        break;
                }
            } else {
                switch (ch) {
                    case '\'' :
                        if (escapeSingleQuote) {
                            out.write('\\');
                        }
                        out.write('\'');
                        break;
                    case '"' :
                        out.write('\\');
                        out.write('"');
                        break;
                    case '\\' :
                        out.write('\\');
                        out.write('\\');
                        break;
                    case '/' :
                        if (escapeForwardSlash) {
                            out.write('\\');
                        }
                        out.write('/');
                        break;
                    default :
                        out.write(ch);
                        break;
                }
            }
        }
    }

    private static String hex(char ch) {
        return Integer.toHexString(ch);
    }

    public static String sig(String strId,String strSalt,String strLei){
        String AppSecre=encode(strSalt);
        String sigStr=encode(strId+AppSecre+strLei);
        return sigStr;
    }
    public static String encode(String source){
        //结果字符串
        String result = "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(source.getBytes());
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            result = buf.toString();


        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return result;
    }
}
